package com.u2ds.core.config;

import com.u2ds.core.security.shiro.MyShiroFilterFactoryBean;
import com.u2ds.core.security.shiro.filters.MD5FormAuthenticationFilter;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.authc.credential.PasswordMatcher;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.HashService;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

@Configuration
@ConditionalOnProperty(prefix="shiro", name="enabled", matchIfMissing=false)
public class ShiroConfig implements EnvironmentAware{
	private Environment env;

	@Override
	public void setEnvironment(Environment environment) {
		this.env = environment;
	}
	
	@Bean
	@ConditionalOnWebApplication
	@ConfigurationProperties(prefix="shiro.filter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean(){
		ShiroFilterFactoryBean factory = new MyShiroFilterFactoryBean();
		factory.setSecurityManager(securityManager());
        Map<String, Filter> filterMap = new HashMap<String, Filter>();
        filterMap.put("authc", new MD5FormAuthenticationFilter());
        factory.setFilters(filterMap);
		return factory;
	}
	
	@Bean
	public CacheManager shiroCacheManager(){
		EhCacheManager cm = new EhCacheManager();
		cm.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
		return cm;
	}
	
	@Bean
	public PasswordService passwordService() {
		DefaultPasswordService ps = new DefaultPasswordService();
		ps.setHashService(hashService());
		return ps;
	}
	
	@Bean
	public SessionDAO sessionDao() {
		return new EnterpriseCacheSessionDAO();
	}
	
	@Bean
	public SessionManager sessionManager() {
		final DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setSessionDAO(sessionDao());
		return sessionManager;
	}

	@Bean
	@ConfigurationProperties(prefix = "shiro.encrypt")
	public HashService hashService() {
		return new DefaultHashService();
	}

	@Bean
	public CredentialsMatcher credentialsMatcher() {
		final PasswordMatcher credentialsMatcher = new PasswordMatcher();
		credentialsMatcher.setPasswordService(passwordService());
		return credentialsMatcher;
	}
	
	@Bean
	public DefaultWebSecurityManager securityManager(){
		final DefaultWebSecurityManager sc = new DefaultWebSecurityManager();
		sc.setCacheManager(shiroCacheManager());
		sc.setSessionManager(sessionManager());
		return sc;
	}
	
	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
		return new LifecycleBeanPostProcessor();
	}
	
	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
		final AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		advisor.setSecurityManager(securityManager());
		return advisor;
	}
	
	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
		final DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
		daap.setProxyTargetClass(true);
		return daap;
	}
	
}
























